<?php

namespace Aspic\Service;

use Aspic\Exception;

/**
 * Represent a service
 *
 * For constructor dependency, if set for service, is always the first in dependencies array
 */
class Service {

	use \Aspic\Preset\OptionTrait;

	/**
	 * Service will act as singleton, only one object will be created and
	 * give at each call to get() on the service manager.
	 */
	const TYPE_SINGLETON = 'singleton';

	/**
	 * ServiceManager will create an new instance of the service each time
	 * it is requested.
	 */
	const TYPE_INSTANCE = 'instance';

	protected $_dependencies;

	protected $_name;

	protected $_type;

	protected $_className;

    /**
     *
     * @param type $className
     * @param string $name Could be null and set further when adding to ServiceManager
     * @param \Aspic\Service\type|string $type $type
     * @param array $dependencies
     */
	public function __construct($className, $name = null, $type = self::TYPE_SINGLETON, array $dependencies = array()) {
		$this->_name = $name;
		$this->_type = $type;
		$this->_name = $className;
		$this->dependencies = $dependencies;
	}

	/**
	 * Proxy method to dependencies
	 */
	public function set_dependencies(array $dependencies) {
		foreach ($dependencies as $dependency) {
			$this->addDependency($dependency);
		}
	}

	public function addDependency(Dependency $dependency) {
		if ($dependency->type == Dependency::TYPE_CONSTRUCTOR_PARAMS) {
			// There cannot be 2 dependencies of this type
			if ($this->getConstructorDependency()) {
				throw new Exception('There cannot be 2 dependencies of type "TYPE_CONSTRUCTOR_PARAMS"');
			}
			else {
				// Constructor dep always first element
				array_unshift($this->_dependencies, $dependency);
			}
		}
		else {
			$this->_dependencies[] = $dependency;
		}
	}

	/**
	 * @return Dependency|null
	 */
	public function getConstructorDependency() {
		if (isset($this->_dependencies[0]) AND $this->dependencies[0]->type == Dependency::TYPE_CONSTRUCTOR_PARAMS) {
			return $this->dependencies[0];
		}
		else {
			return null;
		}
	}

    /**
     * Return dependencies from type
     *
     * @param $type
     * @return Dependency[]
     */
	public function getDependenciesByType($type) {
		return array_filter($this->_dependencies, function(Dependency $dep) use ($type) {
			return $dep->type == $type;
		});
	}

	public function getServiceDependencies() {
		return $this->_dependencies;
	}

	public function getServiceName() {
		return $this->_name;
	}

	public function geClassName() {
		return $this->_className;
	}

	/**
	 * Return the type of the service which is used for instanciation type
	 *
	 * @return string
	 */
	public function getServiceType() {
		return $this->_type;
	}

}
